#ifndef NET_CONNECTOR_H
#define NET_CONNECTOR_H

#include "Sockaddr.h"
#include "utility/Noncopyable.h"

#include <functional>
#include <memory>

class Eventloop;
class IOchannel;
class Socket;

class Connector final : public std::enable_shared_from_this<Connector>
{
private:
    /// @code
    ///      |
    ///     Connector()
    ///      V
    /// _DISCONNECTED <------------------
    ///      |                 |        |
    ///     _start_in_loop()  stop()   restart()
    ///      V                 |     / _reconnect()
    /// _CONNECTING --------------------^
    ///      |                          |
    ///     _channel->_writeCallback()  |
    ///      V                          |
    /// _CONNECTED ----------------------
    enum class _State{ _DISCONNECTED, _CONNECTING, _CONNECTED };



public:
    using NEWConnectionCallback = std::function<void(std::unique_ptr<Socket> &&)>;

    Connector(Eventloop &loop, Sockaddr addr, bool retry = true);
    ~Connector();

    const Sockaddr &addr() const { return _addr; }
    
    void set_new_connection_callback(const NEWConnectionCallback &callback);

    /// @brief run in owner's thread
    void restart();

    void start();
    void stop();

private:
    NONCOPYABLE(Connector);

    void _after_connect(int fd, int connectResult);
    void _after_connected(int fd);
    void _error_callback();
    int _remove_and_reset_channel();
    void _reconnect(int fd);
    void _start_in_loop();
    const char *_state_to_string() const;
    void _write_callback();

    NEWConnectionCallback _newConnectionCallback;
    Eventloop &_loop;
    std::unique_ptr<IOchannel> _channel;
    double _retryDelay;
    const Sockaddr _addr;
    _State _state;
    bool _connecting;
    bool _retry;

};





#endif